<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>闭包</title>
</head>
<body>
    <script>
        var a = 13;
       function fn () {
            var a = 14
            // a => 14
        }
        // console.log(fn());
        // a => 13
        // 一、函数内形成私有内存，会把内存中所有私有变量保护起来， 和外面的没有任何关系 函数执行的这种保护机制 就是闭包
        // 二、保存

        // 闭包的量大作用
        // 1.保护（私有变量和外界变量没有必然联系）
        // 2.保存（形成不销毁的栈内存，里面的私有变量等信息保存下来）

        /**
         * @closure 闭包的两大作用
         * @params 
        */
        // undefined , undefined , undefined

        // 10, 13 , undefined X Error 14

        // 100, 13, 200

        // 12 , undefined , 200



        // var arr = [12, 23]
        // function fn (arr) {
        //     console.log(arr); // [12, 23]
        //     arr[0] = 100
        //     arr = [100]
        //     arr[0] = 0
        //     console.log(arr); // [0]
        // }
        // fn(arr)
        // console.log(arr); // [100, 23]

        
        var n = 1
        function fn () {
            var n = 2 // 1
            function f () {
                n--
                // console.log(n, 1); // fn 的 1
            }
            f()
            return f
        }
        var x = fn()
        x()
        // console.log(n, 'log'); // 0 ｜｜ 1
        // 函数的作用域时创建时候的作用域


        var i = 0
        function A() {
            var i = 10
            function x() {
                // console.log(i);
            }
            return x;
        }
        var y = A();
        y() // 10

        function B() {
            var i = 20
            y()
        }
        B() // 10

        var i = 5
        function fn2(i) {
            return function (n) {
                console.log(n + (++i));
            }
        }
        var f3 = fn2(1)
        console.log(f3);
        f3(2)
        fn2(3)(4)
        fn2(5)(6)
        f3(7)
        console.log(i);

        // 闭包作用域  关于内存释放问题
            // 栈内存
            // 函数执行就会形成栈内存（从内存中分配一块空间）
            // 如果内存都不销毁释放，很容易导致栈内存溢出（内存爆满，电脑卡死）

            // 堆内存 释放
            // 创建一个引用类型的值 就会产生一个堆内存
            // 想要释放对内存 就需要手动解除变量和值的关联（null）
            let obj = { name: 'zw' }
            let oob = obj
            // 释放内存
            obj = null
            oob = null

            // 栈内存 释放
            // 1.打开浏览器会形成新的全局作用域 是栈内存
            // 2.手动执行函数形成的私有作用域是栈内存
            // 3.基于es6中的let/const形成的块级作用域 也是栈内存
            // ...

            /**
             * 全局栈内存： 关掉页面 或者刷新页面（重新生成新的作用域）
             * 私有栈内存： 
             *      1.一般情况下 函数执行完毕后 形成的私有栈内存 就会被销毁
             *      2.栈内存中的某个东西被 私有作用域 以外 的事物占用了则当前栈内存 不能被立即释放销毁
             *          私有作用域中的私有变量信息也会被保留下来
             *      
            */
            function fn2 () {}
            fn2() // 函数执行完毕栈内存销毁 （排除递归 死循环）

            function X () {
                return function xx() {
                }
            }
            let f2 = X()
            // f占用了x执行形成的 栈内存中的一个东西  小函数的地址 则X形成的栈内存 不能被释放
            f2 = null // 释放内存 闭包
    </script>
</body>
</html>